#include "Dri_TIM1.h"
#include <stdio.h>

/**
 * @brief TIM1 初始化 
 */
void Dri_TIM1_Init(void)
{
    // 1. 时钟使能 ------------------------------
    // 1.1 TIM1 时钟使能
    RCC->APB2ENR |= RCC_APB2ENR_TIM1EN;
    // 1.2 GPIOA 时钟使能
    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;

    // 2. GPIO 配置 ------------------------------
    // 配置 TIM1_CH1(PA8) 为复用推挽输出 MODE=11 CNF=10
    GPIOA->CRH |= GPIO_CRH_MODE8;
    GPIOA->CRH |= GPIO_CRH_CNF8_1;
    GPIOA->CRH &= ~GPIO_CRH_CNF8_0;

    // 3. TIM1 时基单元设置和重复计数器设置 ---------
    // 3.1 PSC 设置，实现 100us 计1个数
    TIM1->PSC = 7199;
    // 3.2 ARR 设置，实现计 5000 个数溢出1次 (5000 * 100us = 500ms)
    TIM1->ARR = 4999;
    // 3.3 重复计数器设置，溢出5次产生更新事件
    TIM1->RCR = 4;

    // 4. TIM1 输出比较设置 -------------------------
    // 4.1 设置 CH1 为输出比较 (CCMR1.CC1S=00)
    TIM1->CCMR1 &= ~TIM_CCMR1_CC1S;
    // 4.2 设置 CH1 为 PWM1 模式 (CCMR1.OC1M=110)
    TIM1->CCMR1 |= TIM_CCMR1_OC1M_2;
    TIM1->CCMR1 |= TIM_CCMR1_OC1M_1;
    TIM1->CCMR1 &= ~TIM_CCMR1_OC1M_0;
    // 4.3 设置 CH1 有效电平是高电平 (CCER.CC1P=0)
    TIM1->CCER &= ~TIM_CCER_CC1P;
    // 4.4 设置 CH1 使能 (CCER.CC1E=1)
    TIM1->CCER |= TIM_CCER_CC1E;
    // 4.5 设置主输出使能 (BDTR.MOE=1)
    TIM1->BDTR |= TIM_BDTR_MOE;
    // 4.6 设置占空比为50% (CCR1=ARR/2)
    TIM1->CCR1 = 2500;

    // 5. 中断设置 ---------------------------------
    // 5.1 使能更新中断 (DIER.UIE=1)
    TIM1->DIER |= TIM_DIER_UIE;
    // 5.2 软件产生一次更新事件，让PSC、RCR 的值更新至影子寄存器 (EGR.UG=1)
    TIM1->EGR |= TIM_EGR_UG;

    // 6. NVIC 设置 --------------------------------
    NVIC_SetPriorityGrouping(3);
    NVIC_SetPriority(TIM1_UP_IRQn, 3);
    NVIC_EnableIRQ(TIM1_UP_IRQn);

}

/**
 * @brief TIM1 启动
 */
void Dri_TIM1_Start(void)
{
    // 使能计数 (CR1.CEN=1)
    TIM1->CR1 |= TIM_CR1_CEN;
}

/**
 * @brief TIM1 停止
 */
void Dri_TIM1_Stop(void)
{
    // 关闭计数使能 (CR1.CEN=0)
    TIM1->CR1 &= ~TIM_CR1_CEN;
}

/****************************************************************************/
// 定义 TIM1_UP 的中断服务函数
void TIM1_UP_IRQHandler(void)
{
    printf("TIM1_UP_IRQHandler\n");

    // 1. 清除更新标志位
    TIM1->SR &= ~TIM_SR_UIF;
    // 2. 停止TIM1
    Dri_TIM1_Stop();
}
